package com.jetpack.mvvm.lib.module.process

import com.google.auto.service.AutoService
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import javax.annotation.processing.*
import javax.lang.model.SourceVersion
import javax.lang.model.element.Element
import javax.lang.model.element.TypeElement
import javax.lang.model.util.Elements
import javax.lang.model.util.Types
import javax.tools.Diagnostic.Kind.NOTE

@AutoService(Processor::class)
class AppModuleProcessor : AbstractProcessor() {
    companion object {
        private const val TAG = "AppModuleProcessor::Compiler"
    }

    private var isInit: Boolean = false
    private var moduleName: String? = null
    private lateinit var messager: Messager

    // 节点工具类 (类、函数、属性都是节点) 用来获取节点
    private lateinit var elementUtils: Elements
    private lateinit var typeUtils: Types

    @Synchronized
    override fun init(processingEnv: ProcessingEnvironment) {
        super.init(processingEnv)
        messager = processingEnv.messager
        elementUtils = processingEnv.elementUtils
        messager.printMessage(NOTE, "$TAG init")
        processingEnv.options?.let { options ->
            moduleName = options["AROUTER_MODULE_NAME"]
        }
        this.typeUtils = processingEnv.typeUtils
    }

    override fun process(annotations: Set<TypeElement>?, roundEnv: RoundEnvironment?): Boolean {
        if (isInit) return true
        isInit = true

        annotations?.let {
            val env = roundEnv ?: return@let
            val targetClass = Class.forName(ANNOTATION_CLASS).asSubclass(Annotation::class.java)
            val elements = env.getElementsAnnotatedWith(targetClass) ?: return@let
            elements.forEach { element ->
                val simpleName = element.simpleName
                if (moduleName.isNullOrEmpty()) {
                    moduleName = simpleName.toString()
                }
                messager.printMessage(NOTE, "$TAG get $simpleName")
            }
            if (elements.isNotEmpty()) {
                generateModuleClass(elements)
            }
        }

        return isInit
    }

    private fun generateModuleClass(elements: Set<Element>) {
//        class ModuleInitDemo: IModuleInit {
//    override fun cacheModuleClassPath(): List<String> {
//        val moduleList = mutableListOf<String>()
//        moduleList.add("package.ClassName")
//        return moduleList
//    }
//}
//        val returnType = ClassName
        val list = ClassName("kotlin.collections", "List")
        val strClassName = ClassName("kotlin", "String")
        val arrayList = ClassName("kotlin.collections", "ArrayList")
        val arrayListOfStr = arrayList.parameterizedBy(strClassName)
        val returnType = list.parameterizedBy(strClassName)
        val funBuilder = FunSpec.builder("cacheModuleClassPath")
            .addModifiers(KModifier.OVERRIDE)
            .returns(returnType)
            .addStatement("val result = %T()", arrayListOfStr)
        elements.forEach { element ->
//            val type = element.asType()
//            val pkg =  element.javaClass.packageName
//            val simpleName = element.simpleName
            messager.printMessage(NOTE, "${element.toString()}")
            funBuilder.addStatement("result += %S", "$element")
        }
        funBuilder.addStatement("return result")
        val funSpec = funBuilder.build()
        val superInter = ClassName("com.jetpack.mvvm.lib.module.annotation", "IModuleInit")
        val fileName = String.format("%s_%s", MODULE_PREFIX, moduleName?.capitalize())
        val typeSpec = TypeSpec.classBuilder(fileName)
            .addSuperinterface(superInter)
            .addFunction(funSpec)
            .build()

        messager.printMessage(NOTE, "$TAG create $fileName")
        FileSpec.builder(PKG_NAME, fileName)
            .addType(typeSpec)
            .build()
            .writeTo(processingEnv.filer)
//            .writeTo(System.out)
    }

    override fun getSupportedSourceVersion(): SourceVersion {
        return processingEnv.sourceVersion
    }

    override fun getSupportedAnnotationTypes(): MutableSet<String> {
        return mutableSetOf<String>().apply {
            add(ANNOTATION_CLASS)
        }
    }
}